嗨~我是 A Fei,又到了我們愉快的解題時間,讓我們馬上來看看今天的題目:
(題目來源:Codewars)
You are given an array(list) strarr of strings and an integer k. Your task is to return the first longest string consisting of k consecutive strings taken in the array.
Examples:
strarr = ["tree", "foling", "trashy", "blue", "abcdef", "uvwxyz"], k = 2
Concatenate the consecutive strings of strarr by 2, we get:
treefoling (length 10) concatenation of strarr[0] and strarr[1]
folingtrashy (" 12) concatenation of strarr[1] and strarr[2]
trashyblue (" 10) concatenation of strarr[2] and strarr[3]
blueabcdef (" 10) concatenation of strarr[3] and strarr[4]
abcdefuvwxyz (" 12) concatenation of strarr[4] and strarr[5]
Two strings are the longest: "folingtrashy" and "abcdefuvwxyz".
The first that came is "folingtrashy" so
longest_consec(strarr, 2) should return "folingtrashy".
In the same way:
longest_consec(["zone", "abigail", "theta", "form", "libe", "zas", "theta", "abigail"], 2) --> "abigailtheta"
n being the length of the string array, if n = 0 or k > n or k <= 0 return "".
Note
consecutive strings : follow one after another without an interruption
題目要我們將一個含有 n 個字串元素的陣列,依序以 k 個組成後,比較哪個字串比較長。如果一樣長,就回傳第一個值 ,此點非常重要,我當時看漏這個條件所以卡關超久...先貼我的答案:
def longest_consec(strarr, k)
if strarr.length == 0 || k <= 0 || k > strarr.length
""
else
arr = []
i = 0
while i < (strarr.length - k) + 1
arr[i] = strarr.slice(i, k).join("")
i += 1
end
arr.reduce { |memo, word| memo.length >= word.length ? memo : word }
end
end
題目很「貼心」地幫我們寫出了例外條件「n being the length of the string array, if n = 0 or k > n or k <= 0 return ""」,我知道這樣寫很醜,但是為了趕時間直接在 if 判斷中寫死,好讓我專心破解核心部分。
試著在腦海中模擬一下,假設有陣列 [1, 2, 3, 4],要依序取出 [1, 2]、[2, 3]、[3, 4],總共是要重複做三次事,也就是要跑 3 次迴圈,所以「跑幾圈」就是陣列長度 n 減去取出的元素個數 k,別忘了還要 + 1,寫成 while 迴圈就是:
while i < (strarr.length - k) + 1
#do something
i += 1
end
接下來用 slice 方法,可以從原陣列中「切出」一部份,第一個參數是 index,第二個則是你要切的「長度」,這裡就可以從 strarr[0] 開始,切出 k 長度的陣列,再用 join 組成字串,塞進空陣列 arr 裡。
最後,就是用經典的 reduce 方法,兩兩比較 arr 中哪個字串比較長,「勝者」就留下來挑戰下一個,直到最後「存活」下來那一個,就是最長的字串。但是題目有強調,如果碰到一樣長的字串,留下來的是先出現的那個,也就是要寫成 memo.length >= word.length ? memo : word
而非 memo.length > word.length ? memo : word
,這就是我解題鬼打牆最久的地方。
比較評分最高的解法:
def longest_consec(strarr, k)
return "" unless k.between?(1, strarr.length)
strarr.each_cons(k).map(&:join).max_by(&:length) || ""
end
Wow,第一行就用了我沒看過的 between? 方法,不過字面上的意義很好懂,這裡就不深入分析了。而下一行也是讓人眼花撩亂,有兩個沒看過的方法,大哥你是把整本手冊都背起來了嗎?只能先查一下手冊:
1.each_cons 方法,帶入 a,就可以從 Enumerable 迭代取出長度為 a 的值,簡直是為這題量身打造,直接看官網範例:
(1..10).each_cons(3) { |a| p a }
# outputs below
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
[4, 5, 6]
[5, 6, 7]
[6, 7, 8]
[7, 8, 9]
[8, 9, 10]
如果後面沒有接 {} 的話,它會回傳一個枚舉器 enumerator。
map{|el| el.join("")}
,這部分可以等日後再談。好啦,這次的解題紀錄就先到這,最近比較忙沒什麼時間喇賽想梗,希望之後能多一點時間寫文,掰掰啦